#include<iostream>
#include<cstdlib>
#include<string>
#include<vector>
#include<unistd.h>
#include<ctime>
#include"task.h"
#include<sys/types.h>
#include<sys/wait.h>
using namespace std;

enum {
    Usagerro = 1,
    Argerro,
    PipeErro
};

void Usage(const string &proc)
{
    cout << "Usage:" << proc << " " << "-num" << endl;
}

class channel
{
public:
    channel(int wfd,string name,pid_t sub_process_id)
        :_wfd(wfd)
        , _name(name)
        , _sub_process_id(sub_process_id)
        {}
    void channel_debug()
    {
        cout << "_wfd:" << _wfd;
        cout << "_name:" << _name;
        cout << "_sub_process_id:" << _sub_process_id << endl;

    }
    int wfd()
    {
        return _wfd;
    }
    string& name()
    {
        return _name;
    }
    pid_t sub_process_id()
    {
        return _sub_process_id;
    }
    void Close()
    {
        close(_wfd);
    }
    ~channel()
    {}
private:
    int _wfd;//写端文件描述符
    string _name; //管道名
    pid_t _sub_process_id; //管道进程id号
};

class Processpol
{
public:
    Processpol(int sub_process_num)
        :_sub_process_num(sub_process_num)
        {}
    int Createprocess(work_t work)
    {
        vector<int> fds;
        for(int number = 0; number < _sub_process_num; number++)
        {
            int pipefd[2]{0};
            int n = pipe(pipefd);
            if(n < 0)
            {
                return PipeErro;
            }
            pid_t id = fork();
            if(id == 0)
            {
                if(!fds.empty())
                {
                    cout<<"close w fd:";
                    for(auto& fd: fds)
                    {
                        close(fd);
                        cout << fd;
                    }
                    cout << endl;
                }
                //子进程 -> r 0表示读，1表示写
                close(pipefd[1]);
                //读完父进程发的指令，执行
                dup2(pipefd[0], 0); //将管道中的内容消息重定向到键盘中
                work(pipefd[0]);
                exit(0);
            }
            //父进程
            string cname = "channel-" + to_string(number);
            close(pipefd[0]);
            _channels.push_back(channel(pipefd[1],cname,id));
            fds.push_back(pipefd[1]);
        }
        return 1;
    }
    int nextchannel()//负载均衡时分配任务
    {
        static int next = 0;
        int c = next;
        next++;
        next %= _channels.size();
        return c;
    }
    void sendTask(int index,uint32_t code)
    {
        cout << "send code:" << code << " to " << _channels[index].name() << " sub process pid :" << _channels[index].sub_process_id()<<endl;
        write(_channels[index].wfd(),&code,sizeof(code));
    }
    //让子进程退出，关闭通道 写端
    void KillAll()
    {
        for(auto& channel:_channels)
        {
            channel.Close();
            //cout << channel.name() << " close done  " << "sub_pro quit" <<channel.sub_process_id()<<endl;

            //关闭一个回收一个，因为可能会继承父进程的多个写端。
            pid_t pid = channel.sub_process_id();
            pid_t rid = waitpid(pid,nullptr,0);

            if(rid == pid)
            {
                cout << "wait sub_process: " << pid << endl;
            }
            cout << channel.name() << "close done  " << "sub_pro quit" <<channel.sub_process_id()<<endl;
        }
    }
    void Wait()
    {
        // for(auto& channel :_channels)
        // {
        //     pid_t pid = channel.sub_process_id();
        //     pid_t rid = waitpid(pid,nullptr,0);

        //     if(rid == pid)
        //     {
        //         cout << "wait sub_process: " << pid << endl;
        //     }
        // }
    }
    void debug()
    {
        for(auto &channel: _channels)
        {
            channel.channel_debug();
        }
    }
    ~Processpol()
    {}
private:
    int _sub_process_num;//进程通道号
    vector<channel> _channels;//管理多少个通道
};

void Contrl_processpool(Processpol* pro,int cnt)
{
    //发送任务
    while(cnt--)
    {
        int channel = pro->nextchannel();
        uint32_t code = Next();
        pro->sendTask(channel,code);
        sleep(1);
    }
}

int main(int argc,char *argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        return Usagerro;
    }
    int sub_process_num = stoi(argv[1]);
    if(sub_process_num <= 0)
    {
        return Argerro;
    }
    
    srand((unsigned int)time(nullptr));
    Processpol* pro = new Processpol(sub_process_num);
    pro->Createprocess(worker);
    

    //发送任务
    Contrl_processpool(pro,10);
    cout << "task done"<<endl;

    // pro->debug();

    //子进程退出
    pro->KillAll();

    //回收
    pro->Wait();

    delete pro;

    return 0;

}